package com.xx.menu;

import com.xx.FXHdfsApp;
import com.xx.ViewInfo.HdfsView;
import com.xx.hdfs.HdfsInfo;
import com.xx.hdfsFx.promptStage.CreatePrompt;
import com.xx.hdfsFx.promptStage.DeletePrompt;
import com.xx.hdfsFx.promptStage.ErrorPrompt;
import com.xx.hdfsFx.promptStage.RenamePrompt;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.Clipboard;
import javafx.scene.input.ClipboardContent;
import javafx.scene.layout.HBox;
import javafx.scene.text.Text;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import org.apache.hadoop.fs.Path;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Objects;

import static com.xx.util.Util.getResourceUrl;

public class AddContextMenu {
    public ContextMenu cm = new ContextMenu();
    public TreeView<HdfsView> tree;
    private double x;
    private double y;
    private final FXHdfsApp app;
    private HdfsInfo hdfs;

    public AddContextMenu(TreeView<HdfsView> tree, HdfsInfo hdfs, FXHdfsApp app) {
        this.app = app;
        this.tree = tree;
        this.hdfs = hdfs;
        tree.setContextMenu(cm);
        initContextMenu();
    }

    private void initContextMenu() {
        cm.setPrefSize(tree.getPrefWidth(), tree.getPrefHeight());
        Menu create = new Menu();
        createItem(create);
        HBox createHb = new HBox(10);
        ImageView createI = new ImageView(new Image(getResourceUrl("/texture/new.png")));
        createI.setPreserveRatio(true);
        createI.setFitWidth(25);
        Text createT = new Text("新增");
        createHb.getChildren().addAll(createI, createT);
        create.setGraphic(createHb);

        MenuItem copy = new MenuItem();
        copyAction(copy);
        HBox copyHb = new HBox(10);
        ImageView copyI = new ImageView(new Image(getResourceUrl("/texture/copy.png")));
        copyI.setPreserveRatio(true);
        copyI.setFitWidth(25);
        Text copyT = new Text("复制文件路径");
        copyHb.getChildren().addAll(copyI, copyT);
        copy.setGraphic(copyHb);

        MenuItem download = new MenuItem();
        downloadAction(download);
        HBox downloadHb = new HBox(10);
        ImageView downLoadI = new ImageView(new Image(getResourceUrl("/texture/download.png")));
        downLoadI.setPreserveRatio(true);
        downLoadI.setFitWidth(25);
        Text downloadT = new Text("下载");
        downloadHb.getChildren().addAll(downLoadI, downloadT);
        download.setGraphic(downloadHb);

        Menu upload = new Menu();
        uploadAction(upload);
        HBox uploadHb = new HBox(10);
        ImageView uploadI = new ImageView(new Image(getResourceUrl("/texture/upload.png")));
        uploadI.setPreserveRatio(true);
        uploadI.setFitWidth(25);
        Text uploadT = new Text("上传");
        uploadHb.getChildren().addAll(uploadI, uploadT);
        upload.setGraphic(uploadHb);

        MenuItem delete = new MenuItem();
        deleteAction(delete);
        HBox deleteHb = new HBox(10);
        ImageView deleteI = new ImageView(new Image(getResourceUrl("/texture/delete.png")));
        deleteI.setPreserveRatio(true);
        deleteI.setFitWidth(25);
        Text deleteT = new Text("删除");
        deleteHb.getChildren().addAll(deleteI, deleteT);
        delete.setGraphic(deleteHb);

        MenuItem rename = new MenuItem();
        renameAction(rename);
        HBox renameHb = new HBox(10);
        ImageView renameI = new ImageView(new Image(getResourceUrl("/texture/rename.png")));
        renameI.setPreserveRatio(true);
        renameI.setFitWidth(25);
        Text renameT = new Text("重命名");
        renameHb.getChildren().addAll(renameI, renameT);
        rename.setGraphic(renameHb);

        MenuItem refresh = new MenuItem();
        refresh.setOnAction(e -> {
            try {
                app.refresh();
                app.log.addLog(1, "刷新目录.");
            } catch (IOException ex) {
                app.log.addLog(3, "刷新目录失败.");
                throw new RuntimeException(ex);
            }
        });
        HBox refreshHb = new HBox(10);
        ImageView refreshI = new ImageView(new Image(getResourceUrl("/texture/refresh.png")));
        refreshI.setPreserveRatio(true);
        refreshI.setFitWidth(25);
        Text refreshT = new Text("刷新");
        refreshHb.getChildren().addAll(refreshI, refreshT);
        refresh.setGraphic(refreshHb);

        cm.getItems().addAll(create,
                new SeparatorMenuItem(), new SeparatorMenuItem(),
                copy, new SeparatorMenuItem(),
                download, new SeparatorMenuItem(),
                upload, new SeparatorMenuItem(),
                rename, new SeparatorMenuItem(),
                delete, new SeparatorMenuItem(),
                refresh
        );
    }

    private void renameAction(MenuItem rename) {
        rename.setOnAction(e -> {
            TreeItem<HdfsView> clicks = tree.getTreeItem(tree.getSelectionModel().getSelectedIndex());
            if (clicks == null) return;
            if (clicks.getParent() == null) {
                ErrorPrompt errorPrompt = new ErrorPrompt("警告", "试图更改根目录名称");
                errorPrompt.showStage();
                app.log.addLog(3, "试图更改根目录名称.");
                return;
            }
            RenamePrompt renamePrompt = new RenamePrompt("将" + (clicks.getValue().status.isDirectory() ? "目录" : "文件") +
                    "的名称更改为:", clicks.getValue().status.getPath().getName());
            renamePrompt.button.setOnAction(event -> {
                renamePrompt.closeStage();
                Path newPath =
                        new Path(clicks.getValue().status.getPath().getParent() + "/" + renamePrompt.textField.getText().trim());
                if (hdfs.demo.rename(clicks.getValue().status.getPath(), newPath)) {
//                        刷新更改对象的fileStatus.
                    String oldName = clicks.getValue().status.getPath().toString();
                    clicks.getValue().refreshItem(hdfs, newPath);
                    clicks.getParent().getValue().initTableView();
                    tree.refresh();
                    app.log.addLog(1, oldName + "改名为" + newPath);
                } else {
                    ErrorPrompt errorPrompt = new ErrorPrompt("重构错误", "名称修改失败,出现同名文件.");
                    app.log.addLog(3, "改名失败,出现同名文件.");
                    errorPrompt.showStage();
                }
            });
            renamePrompt.showStage();
        });
    }

    private void uploadAction(Menu upload) {
        MenuItem upFile = new MenuItem();
        upFile.setOnAction(event -> upLoad(true));
        HBox upFileHb = new HBox(10);
        ImageView upFileI = new ImageView(new Image(getResourceUrl("/texture/uploadFile.png")));
        upFileI.setPreserveRatio(true);
        upFileI.setFitWidth(25);
        Text upFileT = new Text("上传文件");
        upFileHb.getChildren().addAll(upFileI, upFileT);
        upFile.setGraphic(upFileHb);

        MenuItem upDir = new MenuItem();
        upDir.setOnAction(event -> upLoad(false));
        HBox upDirHb = new HBox(10);
        ImageView upDirI = new ImageView(new Image(getResourceUrl("/texture/uploadDir.png")));
        upDirI.setPreserveRatio(true);
        upDirI.setFitWidth(25);
        Text upDirT = new Text("上传目录");
        upDirHb.getChildren().addAll(upDirI, upDirT);
        upDir.setGraphic(upDirHb);

        upload.getItems().addAll(upFile, upDir);
    }

    private void upLoad(Boolean isFile) {
        TreeItem<HdfsView> clicks = tree.getTreeItem(tree.getSelectionModel().getSelectedIndex());
        if (clicks == null) return;
        Stage stage = new Stage();
        File file;
        if (isFile) {
            FileChooser dc = new FileChooser();
            dc.setTitle("选择上传的文件");
            dc.setInitialDirectory(new File("D:" + File.separator));
            file = dc.showOpenDialog(stage);
        } else {
            DirectoryChooser dc = new DirectoryChooser();
            dc.setTitle("选择上传的文件");
            dc.setInitialDirectory(new File("D:" + File.separator));
            file = dc.showDialog(stage);
        }

        if (file == null) return;
        TreeItem<HdfsView> nowDir = clicks.getValue().status.isDirectory() ? clicks : clicks.getParent();
        Path p = nowDir.getValue().status.getPath();
        String old = nowDir.getValue().status.getPath() + "/" + file.getName();

        if (hdfs.demo.uploadFile(new Path(file.getPath()), p)) {
            if (file.isFile()) {
                TreeItem<HdfsView> e1 =
                        new HdfsView(hdfs.demo.getFileStatus(new Path(p + "/" + file.getName())),
                                nowDir.getValue().map, nowDir.getValue().root, nowDir.getValue().expend).item;
                e1.getValue().expendLeaf = true;
                nowDir.getChildren().add(e1);
                nowDir.getValue().initTableView();
                e1.getValue().initTableView();
                app.log.addLog(1, "上传文件" + file.getPath() + "到" + old);
            } else {
                try {
                    app.log.addLog(1, "上传目录" + file.getPath() + "到" + old);
                    app.refresh();
                } catch (IOException ex) {
                    throw new RuntimeException(ex);
                }
            }
        } else app.log.addLog(3, "上传失败.");
    }

    private void downloadAction(MenuItem cp) {
        cp.setOnAction(e -> {
            TreeItem<HdfsView> clicks = tree.getTreeItem(tree.getSelectionModel().getSelectedIndex());
            if (clicks == null) return;
            Stage stage = new Stage();
            DirectoryChooser dc = new DirectoryChooser();
            dc.setTitle("选择保存的文件夹");
            dc.setInitialDirectory(new File("D:" + File.separator));
            File dir = dc.showDialog(stage);
            if (dir == null) return;
            if (hdfs.demo.download(new Path(dir.getPath()), clicks.getValue().status.getPath()))
                app.log.addLog(1,
                        "下载" + clicks.getValue().status.getPath() + (clicks.getValue().status.isDirectory() ? "目录" : "文件") +
                                "到" + dir.getPath());
            else
                app.log.addLog(3, "下载" + clicks.getValue().status.getPath() + (clicks.getValue().status.isDirectory() ? "目录" :
                        "文件") + "到" + dir.getPath() + "失败,出现同名.");
        });
    }

    private void copyAction(MenuItem copy) {
        copy.setOnAction(e -> {
            TreeItem<HdfsView> clicks = tree.getTreeItem(tree.getSelectionModel().getSelectedIndex());
            if (clicks == null) return;
            Clipboard board = Clipboard.getSystemClipboard();
            ClipboardContent content = new ClipboardContent();
            content.putString(clicks.getValue().status.getPath().toString());
            board.setContent(content);
        });
    }

    private void createItem(Menu create) {
        MenuItem file = new MenuItem();
        addFileAction(file);
        HBox fileHb = new HBox(10);
        ImageView fileI = new ImageView(new Image(getResourceUrl("/texture/fileAdd.png")));
        fileI.setPreserveRatio(true);
        fileI.setFitWidth(25);
        Text fileT = new Text("新增文件");
        fileHb.getChildren().addAll(fileI, fileT);
        file.setGraphic(fileHb);


        MenuItem dir = new MenuItem();
        addDirAction(dir);
        HBox dirHb = new HBox(10);
        ImageView dirI = new ImageView(new Image(getResourceUrl("/texture/dir.png")));
        dirI.setPreserveRatio(true);
        dirI.setFitWidth(25);
        Text dirT = new Text("新增目录");
        dirHb.getChildren().addAll(dirI, dirT);
        dir.setGraphic(dirHb);

        create.getItems().addAll(file, dir);

    }

    private void addDirAction(MenuItem dir) {
        dir.setOnAction(e -> {
            TreeItem<HdfsView> clicks = tree.getTreeItem(tree.getSelectionModel().getSelectedIndex());
            if (clicks == null) return;
            TreeItem<HdfsView> nowDir = clicks.getValue().status.isDirectory() ? clicks : clicks.getParent();

            CreatePrompt createPrompt = new CreatePrompt("新建目录:");
            createPrompt.button.setOnAction(event -> {
                createPrompt.closeStage();
                TextField tf = createPrompt.textField;
                String[] split = tf.getText().trim().split("/");
                System.out.println(Arrays.toString(split));
                for (int i = 0; i < split.length; i++) {
                    if (Objects.equals(split[i], "")) {
                        if (i == 0) System.out.println("不能/开头");
                        else if (i == split.length - 1) System.out.println("不能/结尾");
                        else System.out.println("不能包含//");
                        return;
                    }
                }
                Path newDir = new Path(nowDir.getValue().status.getPath() + "/" + tf.getText().trim());
                if (!hdfs.demo.exists(newDir) && hdfs.demo.mkdirs(newDir)) {
//                        当输入的最后一个是/时,去除.
                    if (tf.getText().trim().lastIndexOf("/") == tf.getText().trim().length() - 1)
                        tf.setText(tf.getText(0, tf.getText().length() - 1));
                    addRefresh(nowDir, tf.getText().trim());
                    app.log.addLog(1, "创建目录" + nowDir.getValue().status.getPath() + "/" + tf.getText() + "成功");
                } else {
                    ErrorPrompt errorPrompt = new ErrorPrompt("创建目录失败",
                            "无法创建目录" + nowDir.getValue().status.getPath() + "/" + tf.getText() + "路径下存在同名。");
                    app.log.addLog(3, "创建目录失败,/" + nowDir.getValue().status.getPath() + "/" + tf.getText() + "路径下存在同名。");
                    errorPrompt.showStage();
                }
            });
            createPrompt.showStage();
        });
    }

    private void addFileAction(MenuItem file) {
        file.setOnAction(e -> {
            TreeItem<HdfsView> clicks = tree.getTreeItem(tree.getSelectionModel().getSelectedIndex());
            if (clicks == null) return;
            TreeItem<HdfsView> nowDir = clicks.getValue().status.isDirectory() ? clicks : clicks.getParent();

            CreatePrompt createPrompt = new CreatePrompt("新建文件");
            createPrompt.button.setOnAction(event -> {
                createPrompt.closeStage();
                TextField tf = createPrompt.textField;
                String[] split = tf.getText().trim().split("/");
                System.out.println(Arrays.toString(split));
                for (int i = 0; i < split.length; i++) {
                    if (Objects.equals(split[i], "")) {
                        if (i == 0) System.out.println("不能/开头");
                        else if (i == split.length - 1) System.out.println("不能/结尾");
                        else System.out.println("不能包含//");
                        return;
                    }
                }
                Path newFile = new Path(nowDir.getValue().status.getPath().toString() + "/" + tf.getText().trim());
                if (hdfs.demo.createNewFile(newFile)) {
//                        防止出现..../
                    if (tf.getText().trim().lastIndexOf("/") == tf.getText().trim().length() - 1)
                        tf.setText(tf.getText(0, tf.getText().length() - 1));
                    addRefresh(nowDir, tf.getText().trim());
                    app.log.addLog(1, "创建文件/" + nowDir.getValue().status.getPath() + "/" + tf.getText());
                } else {
                    ErrorPrompt errorPrompt = new ErrorPrompt("创建文件失败",
                            "无法创建文件\n" + nowDir.getValue().status.getPath() + "/" + tf.getText() + "原路径下存在同名。");
                    app.log.addLog(3, "创建文件失败,/" + nowDir.getValue().status.getPath() + "/" + tf.getText() + "原路径下存在同名。");
                    errorPrompt.showStage();
                }
            });
            createPrompt.showStage();
        });
    }

    private void addRefresh(TreeItem<HdfsView> nowDir, String pathS) {
//        nowDir,是当前所处的目录,pathS是剩余未创建的路径.
//        path是当前一层的name.
        String path;
//        确定当前的需要创建的treeItem的path.
        int index = pathS.indexOf('/');
        if (index == -1) path = pathS;
        else path = pathS.substring(0, index);
        Path nowPath = new Path(nowDir.getValue().status.getPath() + "/" + path);
        TreeItem<HdfsView> e1 = null;
//        当前的treeItem是否存在.
        for (TreeItem<HdfsView> child : nowDir.getChildren())
            if (Objects.equals(child.getValue().status.getPath().getName(), path) && child.getValue().status.isDirectory())
                e1 = child;
//        当前这一层treeItem不存在.就需要添加treeItem.
        if (e1 == null) {
//            注意,treeItem是在HdfsView类里面实例化的,而不是自己实例化.
            e1 = new HdfsView(hdfs.demo.getFileStatus(nowPath),
                    nowDir.getValue().map, nowDir.getValue().root, nowDir.getValue().expend).item;
            e1.getValue().expendLeaf = true;
            nowDir.getChildren().add(e1);

            e1.getValue().initTableView();
            nowDir.getValue().initTableView();
        }
//        只要还有/...形式就进入下一层的创建.
        if (index != -1) addRefresh(e1, pathS.substring(index + 1));
    }

    private void deleteAction(MenuItem delete) {
        delete.setOnAction(e -> {
            TreeItem<HdfsView> clicks = tree.getTreeItem(tree.getSelectionModel().getSelectedIndex());
            if (clicks == null) return;
            TreeItem<HdfsView> nowDir = clicks.getValue().status.isDirectory() ? clicks : clicks.getParent();
            DeletePrompt deletePrompt =
                    new DeletePrompt("删除" + (clicks.getValue().status.isDirectory() ? "目录" : "文件") + clicks.getValue().status.getPath().getName() +
                            "?",
                            clicks.getValue().status.isDirectory() ? clicks.getValue().status.getPath().getName() + "中的所有文件和子目录将被删除。 " +
                                    "您可能无法完全撤消此操作!" : "");

            deletePrompt.button.setOnAction(event1 -> {
                deletePrompt.closeStage();
                if (clicks.getParent() == null) {
                    ErrorPrompt errorPrompt = new ErrorPrompt("警告", "你正在试图删除根目录!!!");
                    app.log.addLog(3, "试图删除根目录.");
                    errorPrompt.showStage();
                    return;
                }
                Path p = clicks.getValue().status.getPath();
                if (hdfs.demo.exists(p) && hdfs.demo.delete(p, true)) {

                    nowDir.getValue().map.remove(clicks.getValue().status.getPath().toString());
//                        删除的是不是目录
                    boolean b = nowDir != clicks ? nowDir.getChildren().remove(clicks) :
                            nowDir.getParent().getChildren().remove(clicks);
                    nowDir.getValue().initTableView();
                    app.log.addLog(1, "删除/" + clicks.getValue().status.getPath() + (clicks.getValue().status.isDirectory() ?
                            "目录" :
                            "文件"));
                } else {
                    ErrorPrompt errorPrompt =
                            new ErrorPrompt("删除" + clicks.getValue().status.getPath().getName() + (clicks.getValue().status.isDirectory() ? "目录" :
                                    "文件") +
                                    "失败");
                    errorPrompt.showStage();
                }

            });
            deletePrompt.showStage();
        });
    }
}
